import threading
import time
import tkinter as tk
from datetime import datetime, timedelta

import akshare as ak

# stock_monitor.py 中添加资源处理函数
import sys
import os

import requests


def resource_path(relative_path):
    """ 获取资源的绝对路径 """
    try:
        base_path = sys._MEIPASS  # PyInstaller临时文件夹
    except AttributeError:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# 使用示例
icon_path = resource_path("assets/icon.ico")

class StockMonitor:
    def __init__(self, root):
        self.root = root
        root.title("A股实时情绪指标监控工具(云梦路小贤开发内部专用)")
        root.configure(bg='black')
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        x = (screen_width - 3000) // 2
        y = (screen_height - 30) // 2
        root.geometry(f"3000x30+{x}+{y}")
        self.is_topmost = tk.BooleanVar(value=True)
        self.root.attributes('-topmost', self.is_topmost.get())

        # 去掉标题栏
        self.root.overrideredirect(True)

        # 绑定鼠标事件以实现窗口拖动
        root.bind('<Button-1>', self.start_move)
        root.bind('<B1-Motion>', self.move_window)

        # 创建水平滚动容器
        self.container = tk.Canvas(root, bg='black', highlightthickness=0)
        self.scrollbar = tk.Scrollbar(root, orient="horizontal", command=self.container.xview)
        self.scroll_frame = tk.Frame(self.container, bg='black')

        self.container.configure(xscrollcommand=self.scrollbar.set)
        self.container.pack(side="top", fill="x", expand=True)
        self.scrollbar.pack(side="bottom", fill="x")

        self.container.create_window((0, 0), window=self.scroll_frame, anchor="nw")

        # 初始化数据标签
        self.labels = {}
        self.last_request_time = 0
        self.request_interval = 5
        columns = [
            '上涨家数', '上涨>10%', '上涨7~10%', '下跌家数', '下跌7~10%', '下跌>10%',
            '当日成交额', '较昨日变动', '预测全天成交额', '涨停家数', '跌停家数', '炸板家数', '封板率', '昨首板平均溢价', '昨连板平均溢价', '更新时间'
        ]

        self.row1_frame = tk.Frame(self.scroll_frame, bg='black')

        for col in columns:
            frame = tk.Frame(self.row1_frame, bg='black', padx=5)
            label = tk.Label(frame, text=f"{col}: --", font=('微软雅黑', 12),
                             fg='#FF1717', bg='black')
            label.pack()
            frame.pack(side='left', fill='x')
            self.labels[col] = label

        self.row1_frame.pack(side='top', fill='x')
        # 空白分隔行
        self.separator_frame = tk.Frame(self.scroll_frame, bg='black', height=10)  # 高度可以根据需要调整
        self.separator_frame.pack(side='top', fill='x')

        # 自动调整宽度
        self.scroll_frame.update_idletasks()
        self.container.config(scrollregion=self.container.bbox("all"))

        # 启动数据更新线程
        self.schedule_update()
        self.update_time()

    def start_move(self, event):
        self.x = event.x
        self.y = event.y

    def move_window(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.root.winfo_x() + deltax
        y = self.root.winfo_y() + deltay
        self.root.geometry(f"+{x}+{y}")

    def toggle_topmost(self, event=None):
        new_state = not self.is_topmost.get()
        self.is_topmost.set(new_state)
        self.root.attributes('-topmost', new_state)

    def update_button_text(self, *args):
        self.btn_toggle.config(
            text=f"{'取消置顶' if self.is_topmost.get() else '启用置顶'}"
        )

    def schedule_update(self):
        # 启动各个数据更新线程
        threading.Thread(target=self.update_up_down_data, daemon=True).start()
        threading.Thread(target=self.update_turnover_data, daemon=True).start()
        threading.Thread(target=self.update_zt_data, daemon=True).start()
        threading.Thread(target=self.update_dt_data, daemon=True).start()
        threading.Thread(target=self.update_zb_data, daemon=True).start()
        threading.Thread(target=self.update_yestoday_zt_data, daemon=True).start()

    def update_up_down_data(self):
        while True:
            try:
                up_down_data = self.get_up_down_new()
                up = up_down_data.get('up', 0)
                down = up_down_data.get('down', 0)
                down10 = up_down_data['table'][0].get('value', 0)
                down710 = up_down_data['table'][1].get('value', 0)
                up710 = up_down_data['table'][9].get('value', 0)
                up10 = up_down_data['table'][10].get('value', 0)

                self.root.after(0, self.update_gui, {
                    '上涨家数': up,
                    '上涨>10%': up10,
                    '上涨7~10%': up710,
                    '下跌家数': down,
                    '下跌>10%': down10,
                    '下跌7~10%': down710,
                })
            except Exception as e:
                print("更新涨跌数据失败:", e)
            finally:
                time.sleep(self.request_interval)

    def update_turnover_data(self):
        while True:
            try:
                header_data = self.get_turnover()
                turnover = round(next((item['val'] for item in header_data if item['key'] == 'turnover'), 0) / 1e8, 2)
                turnover_change = round(next((item['val'] for item in header_data if item['key'] == 'turnover_change'), 0) / 1e8, 2)
                predict_turnover = round(next((item['val'] for item in header_data if item['key'] == 'predict_turnover'), 0) / 1e8, 2)

                self.root.after(0, self.update_gui, {
                    '当日成交额': f"{turnover}亿",
                    '较昨日变动': f"{turnover_change:.2f}亿",
                    '预测全天成交额': f"{predict_turnover}亿",
                })
            except Exception as e:
                print("更新成交额数据失败:", e)
            finally:
                time.sleep(self.request_interval)

    def update_zt_data(self):
        while True:
            try:
                zt_count = self.get_realtime_zt_count()
                self.root.after(0, self.update_gui, {
                    '涨停家数': zt_count,
                })
            except Exception as e:
                print("更新涨停数据失败:", e)
            finally:
                time.sleep(self.request_interval)

    def update_dt_data(self):
        while True:
            try:
                dt_count = self.get_realtime_dt_count()
                self.root.after(0, self.update_gui, {
                    '跌停家数': dt_count,
                })
            except Exception as e:
                print("更新跌停数据失败:", e)
            finally:
                time.sleep(self.request_interval)

    def update_zb_data(self):
        while True:
            try:
                zb_count = self.get_realtime_zb_count()
                fbl = round(zb_count / (zb_count + self.labels['涨停家数'].cget('text').split(': ')[1]) * 100) if self.labels['涨停家数'].cget('text').split(': ')[1] != '--' else 0

                self.root.after(0, self.update_gui, {
                    '炸板家数': zb_count,
                    '封板率': f"{fbl}%",
                })
            except Exception as e:
                print("更新炸板数据失败:", e)
            finally:
                time.sleep(self.request_interval)

    def update_yestoday_zt_data(self):
        while True:
            try:
                limit_df = self.get_yestoday_zt()
                first_limit = limit_df[limit_df['昨日连板数'] == 1]
                cont_limit = limit_df[limit_df['昨日连板数'] >= 2]

                avg_first = first_limit['涨跌幅'].mean() if not first_limit.empty else 0
                avg_cont = cont_limit['涨跌幅'].mean() if not cont_limit.empty else 0

                self.root.after(0, self.update_gui, {
                    '昨首板平均溢价': f"{avg_first:.2f}%",
                    '昨连板平均溢价': f"{avg_cont:.2f}%",
                })
            except Exception as e:
                print("更新昨日涨停数据失败:", e)
            finally:
                time.sleep(self.request_interval)

    def update_time(self):
        current_time = datetime.now().strftime("%H:%M:%S")
        self.labels['更新时间'].config(text=f"更新时间: {current_time}")
        self.root.after(1000, self.update_time)  # 每秒更新一次时间

    @staticmethod
    def get_realtime_zt_count():
        try:
            print("正在获取实时涨停数据...")
            date = datetime.now().strftime("%Y%m%d")
            zt_df = ak.stock_zt_pool_em(date=date)
            print(f"获取实时涨停数据成功...")
            return len(zt_df) if not zt_df.empty else 0
        except Exception as e:
            print(f"获取涨停数据异常：{e}")
            return 0

    @staticmethod
    def get_realtime_dt_count():
        try:
            print("正在获取实时跌停数据...")
            date = datetime.now().strftime("%Y%m%d")
            dt_df = ak.stock_zt_pool_dtgc_em(date=date)
            print(f"获取实时跌停数据成功...")
            return len(dt_df) if not dt_df.empty else 0
        except Exception as e:
            print(f"获取跌停数据异常：{e}")
            return 0

    @staticmethod
    def get_realtime_zb_count():
        try:
            print("正在获取实时炸板数据...")
            date = datetime.now().strftime("%Y%m%d")
            zb_df = ak.stock_zt_pool_zbgc_em(date=date)
            zb_df = zb_df[~zb_df['代码'].str.startswith(('43', '83', '87', '88'))]  # 北交所股票代码前缀为bj
            print(f"获取实时炸板数据成功...")
            return len(zb_df) if not zb_df.empty else 0
        except Exception as e:
            print(f"获取炸板数据异常：{e}")
            return 0

    @staticmethod
    def get_today():
        today = datetime.now()
        if today.weekday() == 6:
            today -= timedelta(days=2)
        elif today.weekday() == 5:
            today -= timedelta(days=1)
        return today.strftime("%Y%m%d")

    @classmethod
    def get_yestoday_zt(cls):
        try:
            print("正在获取昨日涨停数据...")
            trade_date = cls.get_today()
            limit_df = ak.stock_zt_pool_previous_em(date=trade_date)

            print(f"获取昨日涨停数据成功...")
            print(f"******************************************************")

            limit_df = limit_df[~limit_df['代码'].str.startswith(('43', '83', '87', '88'))]  # 北交所股票代码前缀为bj
            limit_df = limit_df[~limit_df['名称'].str.contains('ST', na=False)]  # 包含ST或*ST
            limit_df['代码'] = limit_df['代码'].str[2:]

            if limit_df.empty:
                raise ValueError("昨日无有效涨停数据（已过滤北交所）")

            return limit_df

        except Exception as e:
            print(f"获取数据失败: {e}")
            exit()

    def get_up_down_new(self):
        print("正在获取同花顺涨跌数据...")
        url = "https://dq.10jqka.com.cn/fuyao/up_down_distribution/distribution/v2/realtime"
        headers = {
            "Host": "dq.10jqka.com.cn",
            "Connection": "keep-alive",
            "sec-ch-ua-platform": "Android",
            "User-Agent": "Mozilla/5.0 (Linux; Android 15; 2410DPN6CC Build/AQ3A.240812.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.6998.135 Mobile Safari/537.36 Hexin_Gphone/11.26.02 (Royal Flush)",
            "Accept": "application/json, text/plain, */*",
            "sec-ch-ua": '"Chromium";v="134", "Not:A-Brand";v="24", "Android WebView";v="134"',
            "sec-ch-ua-mobile": "?1",
            "Origin": "https://eq.10jqka.com.cn",
            "X-Requested-With": "com.hexin.plat.android",
            "Sec-Fetch-Site": "same-site",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Dest": "empty",
            "Referer": "https://eq.10jqka.com.cn/",
            "Accept-Encoding": "gzip, deflate, br, zstd",
            "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
        }
        try:
            response = requests.get(
                url,
                headers=headers,
                verify=True
            )
            response_data = response.json()
            data = response_data['data']
            print(f"获取同花顺实时涨跌数据成功")
            return data
        except Exception as e:
            print(f"获取同花顺实时涨跌数据失败: {e}")
            return None

    def get_turnover(self):
        print("正在获取同花顺成交额数据...")
        url = "https://dq.10jqka.com.cn/fuyao/market_analysis_api/chart/v1/get_chart_data"
        params = {
            "chart_key": "turnover_minute"
        }

        headers = {
            "Host": "dq.10jqka.com.cn",
            "Connection": "keep-alive",
            "sec-ch-ua-platform": "Android",
            "User-Agent": "Mozilla/5.0 (Linux; Android 15; 2410DPN6CC Build/AQ3A.240812.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/134.0.6998.135 Mobile Safari/537.36 Hexin_Gphone/11.26.02 (Royal Flush)",
            "Accept": "application/json, text/plain, */*",
            "sec-ch-ua": '"Chromium";v="134", "Not:A-Brand";v="24", "Android WebView";v="134"',
            "sec-ch-ua-mobile": "?1",
            "Origin": "https://eq.10jqka.com.cn",
            "X-Requested-With": "com.hexin.plat.android",
            "Sec-Fetch-Site": "same-site",
            "Sec-Fetch-Mode": "cors",
            "Sec-Fetch-Dest": "empty",
            "Referer": "https://eq.10jqka.com.cn/",
            "Accept-Encoding": "gzip, deflate, br, zstd",
            "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7"
        }
        try:
            response = requests.get(
                url,
                params=params,
                headers=headers,
                verify=True
            )
            response_data = response.json()
            header_data = response_data['data']['charts']['header']
            print(f"获取同花顺成交额数据成功")
            return header_data
        except Exception as e:
            print(f"获取同花顺成交额数据失败: {e}")
            return None

    def update_gui(self, data):
        for key in self.labels:
            value = data.get(key, '--')
            self.labels[key].config(text=f"{key}: {value}")


if __name__ == "__main__":
    root = tk.Tk()
    app = StockMonitor(root)
    root.mainloop()
